﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Objects;
using Tizer.Core.Enums;
using Tizer.Utilities;

namespace Tizer.Core.Repository
{
    public class AccountRepository : BaseRepository<Account>
    {
        public AccountRepository(ObjectContext context)
                :base(context)
        {
        }

        public AccountRepository()
        {
        }

        /// <summary>
        /// Получить сущность по Id
        /// </summary>
        /// <returns>Сущность</returns>
        public Account GetById(int id)
        {
            return ObjectSet.SingleOrDefault(e => e.ID == id);
        }

        /// <summary>
        /// Возвращает список аккаунтов
        /// </summary>
        /// <param name="providerUserKey">Идентификатор пользователя</param>
        /// <param name="userIsOnline">Пользователь онлайн</param>
        /// <returns>Список пользователей</returns>
        public IEnumerable<Account> GetAccount(object providerUserKey, bool userIsOnline)
        {
            IEnumerable<Account> userList = null;

            if (providerUserKey != null)
                userList = GetQuery().Where(x => x.ID == (long)providerUserKey).ToList();

            return userList;
        }


        /// <summary>
        /// Получить объект по логину аккаунта
        /// </summary>
        /// <param name="login">Имя аккаунта</param>
        /// <returns>аккаунт</returns>
        public Account GetByLogin(string login)
        {
            if (string.IsNullOrWhiteSpace(login))
                return null;
            Account account = GetQuery().Where(u => (u.IsActive && (u.Login == login.Trim()))).FirstOrDefault();
            return account;
        }

       
        /// <summary>
        /// Сменить пароль для аккаунта
        /// </summary>
        /// <param name="userId">ID аккаунта</param>
        /// <param name="newPassword">Пароль</param>
        /// <returns>аккаунт</returns>
        public Account ChangePassword(int userId, string newPassword)
        {
            if (string.IsNullOrWhiteSpace(newPassword))
                return null;
            Account account = Single(x => x.ID == userId);
            if (account == null)
                return null;

            account.PasswordSalt = PasswordHelper.GeneratePasswordSalt();
            account.PasswordHash = PasswordHelper.HashPassword(newPassword, account.PasswordSalt);

            SaveChanges();
            return account;
        }

        
        /// <summary>
        /// Изменить пароль аккаунта
        /// </summary>
        /// <param name="login">Имя аккаунта</param>
        /// <param name="newPassword">Новый пароль</param>
        /// <param name="oldPassword">Старый пароль</param>
        /// <returns>true если изменен</returns>
        public bool ChangePassword(string login, string newPassword, string oldPassword)
        {
            if (!String.IsNullOrEmpty(login))
            {
                if (Validate(login, oldPassword))
                {
                    if (!String.IsNullOrEmpty(newPassword) && !String.IsNullOrEmpty(oldPassword))
                    {
                        var user = Single(x => x.Login == login);

                        if (user == null)
                            return false;

                        string hashPassword = PasswordHelper.GeneratePasswordSalt();
                        user.PasswordSalt = hashPassword;
                        user.PasswordHash = PasswordHelper.HashPassword(newPassword, hashPassword);
                        SaveChanges();
                        return true;
                    }
                }
            }

            return false;
        }


        /// <summary>
        /// Автоматическая установка нового пароля
        /// </summary>
        /// <param name="login">Логин</param>
        /// <param name="useNumbers">Использовать числа в пароле</param>
        /// <param name="useSpecialSymbols">Использовать специальные символы ($%/\;)</param>
        /// <param name="minSymbols">Минимальная длина пароля</param>
        /// <param name="maxSymbols">Максимальная длина пароля</param>
        /// <returns>Установленный пароль</returns>
        public string SetAutomaticNewPassword(string login, int minSymbols, int maxSymbols, bool useNumbers, bool useSpecialSymbols)
        {
            var generator = new PasswordGenerator
            {
                Minimum = minSymbols,
                Maximum = maxSymbols,
                UseNumbers = useNumbers,
                UseSpecialSymbols = useSpecialSymbols
            };

            var password = generator.GeneratePassword();

            var currentAccount = Single(x => x.Login == login);

            if (currentAccount == null)
            {
                return null;
            }

            if (!String.IsNullOrEmpty(password))
            {
                string salt = PasswordHelper.GeneratePasswordSalt();
                string hashPassword = PasswordHelper.HashPassword(password, salt);
                currentAccount.PasswordSalt = salt;
                currentAccount.PasswordHash = hashPassword;
                SaveChanges();
            }
            else
            {
                return null;
            }

            return password;
        }

        /// <summary>
        /// Проверка аккаунта на существование в БД
        /// </summary>
        /// <param name="login">Имя аккаунта</param>
        /// <returns>TRUE - существует</returns>
        public bool IsExsist(string login)
        {
            if (string.IsNullOrEmpty(login)) return false;
           
            Account account = Single(x => x.Login == login.Trim());
            return account != null;
        }

        /// <summary>
        /// Проверка аккаунта
        /// </summary>
        /// <param name="login">Логин аккаунта</param>
        /// <param name="password">Пароль</param>
        /// <returns></returns>
        public bool Validate(string login, string password)
        {
            if (string.IsNullOrWhiteSpace(login) && string.IsNullOrWhiteSpace(password))
                return false;

            Account account = Single(x => x.Login == login);

            if (account == null)
                return false;
            if (!account.IsActive)
                return false;

            string passwordHash = PasswordHelper.HashPassword(password, account.PasswordSalt);
            return passwordHash == account.PasswordHash;
        }

        /// <summary>
        /// Блокировка/разблокировка аккаунта
        /// </summary>
        /// <param name="id">ID аккаунта</param>
        /// <param name="active">Блокировать/разблокировать</param>
        public void Block(int id, bool active)
        {
            Account account = Single(x => x.ID == id);
            if (account == null) return;
            account.IsActive = active;
            SaveChanges();
        }

        /// <summary>
        /// Заблокировать аккаунт
        /// </summary>
        /// <param name="login">Имя аккаунта</param>
        /// <returns>true- если заблокирован</returns>
        public bool Block(string login)
        {
            Account account = Single(x => x.Login == login);
            if (account == null) return false;
            account.IsActive = false;
            SaveChanges();
            return true;
        }

        /// <summary>
        /// Разблокировать аккаунта
        /// </summary>
        /// <param name="login">Имя аккаунта</param>
        /// <returns>true - если разблокирован</returns>
        public bool UnBlock (string login)
        {
            Account account = Single(x => x.Login == login);
            if (account == null) return false;
            account.IsActive = true;
            SaveChanges();
            return true;
        }

        public Account Create (string login, string password, AccountType accountType)
        {
            if (!string.IsNullOrEmpty(login) && !string.IsNullOrEmpty(password))
            {
                string passwordSalt = PasswordHelper.GeneratePasswordSalt();
                string passwordHash = PasswordHelper.HashPassword(password, passwordSalt);
                
                var account = new Account
                                  {
                                      AccountType = accountType,
                                      IsActive = true,
                                      IsApproved = true,
                                      Login = login,
                                      PasswordSalt = passwordSalt,
                                      PasswordHash = passwordHash,
                                      CreatedDate = DateTime.Now,
                                      LastLockedOutDate = DateTime.Now,
                                      LastLoginDate = DateTime.Now
                                  };
                Add(account);
                return account;
                
            }
            return null;
        }

        /// <summary>
        /// Удалить 
        /// </summary>
        /// <param name="id">ID менеджера</param>
        public void Delete(int id)
        {
            Account account = Single(x => x.ID == id);
            if (account == null) return;

            Delete(account);
            SaveChanges();
        }
    }
}
